﻿using System;
using System.Net;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Threading;
using System.Reflection;
using System.Runtime.Serialization;

namespace RStein.PosterousReader.Common.ViewModelsHelpers
{
  [DataContract]
  public class PropertyNotificationBase : INotifyPropertyChanged
  {
    public event PropertyChangedEventHandler PropertyChanged;
   
    public PropertyNotificationBase()
    {
      SuppressPropertyChangedNotification = false;            
    }

    [NonTransientState]
    public SynchronizationContext SynchContext
    {
      get;
      set;
    }
    
    public bool SuppressPropertyChangedNotification
    {
      get;
      set;
    }

    public virtual void RaisePropertyChangedEvent(string propertyName)
    {
      var eargs = new PropertyChangedEventArgs(propertyName);
      OnPropertyChanged(eargs);

    }

    public virtual void RaisePropertyChangedEvent<TReturn>(Expression<Func<TReturn>> propertyDefinition)
    {
      if (propertyDefinition == null)
      {
        throw new ArgumentNullException("propertyDefinition");
      }

      var memberExpression = propertyDefinition.Body as MemberExpression;

      if (memberExpression == null)
      {
        throw new ArgumentException("propertyDefinition");
      }

      RaisePropertyChangedEvent(memberExpression.Member.Name);

    }

    public virtual void RaiseAllPropertiesChanged()
    {
      GetType()
      .GetProperties(BindingFlags.Public | BindingFlags.Instance)
      .ToList()
      .ForEach(property => RaisePropertyChangedEvent(property.Name));
    }

    public virtual void RaisePropertiesChanged(params string[] properties)
    {
      properties.ToList().ForEach(property => RaisePropertyChangedEvent(property));
    }
    
    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
      if (SuppressPropertyChangedNotification)
      {
        return;
      }

      if (PropertyChanged == null)
      {
        return;
      }
      
      var PropertyChangedHandler = PropertyChanged;
      if (SynchContext != null)
      {
        SynchContext.Send(state => PropertyChangedHandler(this, e), null);
      }
      else
      {
        PropertyChangedHandler(this, e);
      }

    }    

  }
}
